﻿/*
 * 名称：MD5计算，返回128位，32个字符。
 * 简介：提供了三个方法：分别对字节数组，字符串和文件进行MD5计算。
 * 
 * 2011/08/06	建立此类，提供三个相应操作函数。
 * 2013/09/06 如果输入为空，则返回为默认字符串：abcdefghijk0123456789。
 * 2018/12/29 如果文件大于100M，计算结果未必准确。
 * 
*/

using System.Text;
using System.Security.Cryptography;
using System.IO;

namespace WindGoes6.Security
{
	/// <summary>
	/// MD5处理类，能计算文件，字符串和数字等的MD5.
	/// </summary>
	public class MD5Helper
	{
		/// <summary>
		/// 计算给定字节数据的MD5码。
		/// </summary>
		/// <param name="data"></param>
		/// <returns></returns>
		public static string BytesHash(byte[] data)
		{
			if (data == null || data.Length == 0)
				return "abcdefghijk0123456789";

			MD5 md5 = new MD5CryptoServiceProvider();
			byte[] hashed_data = md5.ComputeHash(data);
			StringBuilder sBuilder = new StringBuilder();
			for (int i = 0; i < hashed_data.Length; i++)
				sBuilder.Append(hashed_data[i].ToString("x2"));
			return sBuilder.ToString();
		}

		/// <summary>
		/// 计算给定字符串的MD5码。
		/// </summary>
		/// <param name="str"></param>
		/// <returns></returns>
		public static string StringHash(string str)
		{
			if (string.IsNullOrEmpty(str))
				return "abcdefghijk0123456789";

			byte[] data = Encoding.Default.GetBytes(str);
			MD5 md5 = new MD5CryptoServiceProvider();
			byte[] hashed_data = md5.ComputeHash(data);
			StringBuilder sBuilder = new StringBuilder();
			for (int i = 0; i < hashed_data.Length; i++)
				sBuilder.Append(hashed_data[i].ToString("x2"));
			return sBuilder.ToString();
		}

		/// <summary>
		/// 对一个文件计算Hash，如果计算失败则返回null。
		/// </summary>
		/// <param name="path">需要计算MD5码的文件的完整路径。</param>
		/// <returns></returns>
		public static string FileHash(string path)
		{
			if (!File.Exists(path))
				return null;

			string md5code = null;
			try
			{

				using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
				{
					//如果是大于10M的文件，那么只读取前10M的数据。
					long maxlen = 100 * 1024 * 1024;
					byte[] bts = new byte[fs.Length > maxlen ? maxlen : fs.Length];
					fs.Read(bts, 0, bts.Length);
					md5code = BytesHash(bts);
				}
			}
			catch
			{
				md5code = null;
			}
			return md5code;
		}
	}
}
